package prickworlds.game;

import static org.lwjgl.opengl.GL11.*;
import prickworlds.Prickworlds;
import prickworlds.game.Bonus.ReloadSpeedUp;
import prickworlds.game.templates.RobotTemplate;
import prickworlds.game.templates.WeaponTemplate;
import prickworlds.graphics.Texture;
import prickworlds.physics.RectRigidBody;

/**
 * This class represents a robot
 * 
 * @author Faruk Acibal, Richard Dziambor, Christian Holzreuter, Nicolas Winkler
 * 
 */
public class Robot extends MovingSolidObject {
	/**
	 * current level
	 */
	int level;

	/**
	 * the number of the team
	 */
	int team = 0;

	/**
	 * when {@code reloadState == 0}, a new bullet is shot and
	 * {@code reloadState} is set to another value
	 */
	int reloadState;

	/**
	 * the direction in which the robot is looking
	 */
	float lookAngle;

	/**
	 * the direction in which the robot is moving
	 */
	float moveAngle;

	/**
	 * current hitpoints
	 */
	int hitPoints;

	/**
	 * max hitpoints
	 */
	int maxPoints;

	/**
	 * true if the robot got destroyed
	 */
	boolean destroyed;

	/**
	 * x-Coordinate of the target
	 */
	float targetX;

	/**
	 * Y-Coordinate of the target
	 */
	float targetY;

	RobotTemplate template;
	WeaponTemplate activeWeapon;

	enum Bonus {
		RELOAD_SPEED
	}

	/**
	 * default constructor
	 */
	public Robot(RobotTemplate template) {
		this(template, 0, 0, 0, 0);
	}

	/**
	 * creates a {@link Robot} at the specified position
	 * 
	 * @param posX
	 * @param posY
	 */
	public Robot(RobotTemplate template, float posX, float posY,
			int maxHitPoints, int team) {
		super(posX, posY);
		this.activeWeapon = template.getStandardWeapons()[0];
		this.hitPoints = template.getMaxHp();
		this.maxPoints = template.getMaxHp();
		destroyed = false;
		reloadState = 0;
		this.template = template;
		this.team = team;
		super.setHitbox(new RectRigidBody(-1, -1, 2, 2));
	}

	/**
	 * updates position and rotation
	 */
	@Override
	public void update() {
		moveAngle = (float) Math.atan2(velY, velX);
		if (reloadState > 0)
			reloadState--;
		super.update();
	}

	/**
	 * displays the robot
	 */
	@Override
	public void display() {
		glColor3f(1.0f, 1.0f, 1.0f);

		if (template == null) {
			glPushMatrix();
			glTranslatef(posX, posY, 0.0f);
			glRotatef(moveAngle * 180 / (float) Math.PI, 0.0f, 0.0f, 1.0f);
			glBegin(GL_TRIANGLE_STRIP);

			glVertex2f(-1.0f, -1.0f);
			glVertex2f(1.0f, -1.0f);
			glVertex2f(-1.0f, 1.0f);
			glVertex2f(1.0f, 1.0f);

			glEnd();
			glPopMatrix();

			glColor3f(0.2f, 0.0f, 0.7f);
			glPushMatrix();
			glTranslatef(posX, posY, 0.0f);
			glRotatef(lookAngle * 180 / (float) Math.PI, 0.0f, 0.0f, 1.0f);
			glBegin(GL_TRIANGLE_STRIP);

			glVertex2f(-1.0f, -1.0f);
			glVertex2f(1.0f, -1.0f);
			glVertex2f(-1.0f, 1.0f);
			glVertex2f(1.0f, 1.0f);

			glEnd();
			glPopMatrix();
		} else {
			Texture lower = template.getLowerTexture();
			Texture upper = template.getUpperTexture();

			glColor3f(1f, 1f, 1f);

			glPushMatrix();
			glTranslatef(posX, posY, 0.0f);
			glRotatef(moveAngle * 180 / (float) Math.PI, 0.0f, 0.0f, 1.0f);

			lower.display(-1, -1, 2, 2);

			glPopMatrix();
			glPushMatrix();
			glTranslatef(posX, posY, 0.0f);
			glRotatef(lookAngle * 180 / (float) Math.PI, 0.0f, 0.0f, 1.0f);

			upper.display(-1, -1, 2, 2);

			glPopMatrix();
		}

	}

	/**
	 * calculates the angle to a point
	 * 
	 * @param x
	 *            the x-coordinate of the point
	 * @param y
	 *            the y-coordinate of the point
	 * @return the angle to the point
	 */
	protected float getAngleTo(float x, float y) {
		return (float) Math.atan2(y - this.posY, x - this.posX);
	}

	/**
	 * makes the robot look in the direction of the specified point (in map
	 * coordinates)
	 * 
	 * @param posX
	 *            the x-coordinate of the point
	 * @param posY
	 *            the y-coordinate of the point
	 */
	public void setLookAt(float posX, float posY) {
		this.lookAngle = getAngleTo(posX, posY);
	}

	public void addDamage(int damage) {
		hitPoints -= damage;
		if (hitPoints <= 0) {
			destroy();
		}
	}

	public void destroy() {
		destroyed = true;
	}

	public boolean isDestroyed() {
		return destroyed;
	}

	public void setDestroyed(boolean destroyed) {
		this.destroyed = destroyed;
	}

	public void requestShot() {
		if (reloadState <= 0) {
			Prickworlds.getGame().getMap()
					.createBullet(this, activeWeapon, targetX, targetY, team);
			reloadState = activeWeapon.getReloadTime();
		}
	}

	public int getReloadTime() {
		return activeWeapon.getReloadTime();
	}

	public int getLife() {
		return hitPoints;
	}

	public void addReloadBonus(ReloadSpeedUp reloadSpeedUp) {
		activeWeapon.setReloadTime(activeWeapon.getReloadTime() - 1);
	}

	public RobotTemplate getTemplate() {
		return template;
	}

	public void restoreFullHealth() {
		hitPoints = template.getMaxHp();
	}
}
